package com.atguigu.crowd.until;

import com.aliyun.api.gateway.demo.util.HttpUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.PutObjectResult;
import com.atguigu.crowd.constant.CrowdConstant;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 爱众筹项目通用的工具方法类
 *
 * @author Jie
 */
public class CrowdUtil {

    /**
     * 负责上传文件至OSS服务器的方法
     * @param endpoint          OSS参数
     * @param accessKeyId       OSS参数
     * @param accessKeySecret   OSS参数
     * @param inputStream       要上传文件的输入流
     * @param bucketName        OSS参数
     * @param bucketDomain      OSS参数
     * @param originalName      要上传的文件的原始文件名
     * @return                  包含上传结果以及上传的文件在OSS上的访问路径
     */
    public static ResultEntity<String> uploadFileToOss(String endpoint, String accessKeyId, String accessKeySecret,
                                                       InputStream inputStream, String bucketName, String bucketDomain,
                                                       String originalName) {

        // 创建 OSSClient 实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 生成上传文件的目录
        String folderName = new SimpleDateFormat("yyyyMMdd").format(new Date());

        // 生成上传文件在 OSS 服务器上保存时的文件名
        // 原始文件名：beautfulgirl.jpg
        // 生成文件名：wer234234efwer235346457dfswet346235.jpg
        // 使用 UUID 生成文件主体名称
        String fileMainName = UUID.randomUUID().toString().replace("-", "");

        // 从原始文件名中获取文件扩展名
        String extensionName = originalName.substring(originalName.lastIndexOf("."));

        // 使用目录、文件主体名称、文件扩展名称拼接得到对象名称
        String objectName = folderName + "/" + fileMainName + extensionName;

        try {

            // 调用 OSS 客户端对象的方法上传文件并获取响应结果数据
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, inputStream);

            // 从响应结果中获取具体响应消息
            ResponseMessage responseMessage = putObjectResult.getResponse();

            // 根据响应状态码判断请求是否成功
            if (responseMessage == null) {

                // 拼接访问刚刚上传的文件的路径
                String ossFileAccessPath = bucketDomain + "/" + objectName;
                // 当前方法返回成功
                return ResultEntity.successWithData(ossFileAccessPath);
            } else {

                // 获取响应状态码
                int statusCode = responseMessage.getStatusCode();
                // 如果请求没有成功，获取错误消息
                String errorMessage = responseMessage.getErrorResponseAsString();
                // 当前方法返回失败
                return ResultEntity.failed(" 当 前 响 应 状 态 码 =" + statusCode + " 错 误 消 息 = "+errorMessage);
            }
        } catch (Exception e) {

            e.printStackTrace();
            // 当前方法返回失败
            return ResultEntity.failed(e.getMessage());
        } finally {

            if (ossClient != null) {
                // 关闭 OSSClient。
                ossClient.shutdown();
            }
        }

    }


    /**
     * 给第三方接口发送请求将验证码发送至用户手机
     *
     * @param host          接口地址
     * @param path          具体发送短信功能的地址
     * @param method        请求方式
     * @param appcode       购买第三方接口的appcode
     * @param phoneNumber   需要发送短信的手机号
     * @param smsTemplateNo 模板代码
     * @param smsSignId     签名ID
     * @return 成功则返回验证码，失败返回错误信息
     */
    public static ResultEntity<String> sendShortMessage(String host, String path, String method, String appcode,
                                                        String phoneNumber, String smsTemplateNo, String smsSignId) {

        Map<String, String> headers = new HashMap<String, String>();

        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);

        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

        //需要给X-Ca-Nonce的值生成随机字符串，每次请求不能相同
        headers.put("X-Ca-Nonce", UUID.randomUUID().toString());

        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();

        // 默认值为 false，若传true则过滤虚拟手机号。
        bodys.put("filterVirtual", "false");

        // 手机号
        bodys.put("phoneNumber", phoneNumber);

        // 请求流水号，可用于交易流水查询
        bodys.put("reqNo", "miitangtest01");

        // 短信签名ID,测试时可以使用签名ID为0000的测试签名
        bodys.put("smsSignId", smsSignId);

        // 验证码短信内模板：验证码模板编号，不传时使用默认模板。
        bodys.put("smsTemplateNo", smsTemplateNo);

        // 生成六位数的随机验证码
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            int random = (int) (Math.random() * 10);
            stringBuilder.append(random);
        }
        String verifyCode = stringBuilder.toString();
        // 验证码:不传此参数时可由接口提供方生成6位数字验证码
        bodys.put("verifyCode", verifyCode);

        try {

            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);

            // 获取状态码
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            String reasonPhrase = statusLine.getReasonPhrase();

            // 打印当前接口状态
            System.out.println(EntityUtils.toString(response.getEntity()));
            // 如果状态码等于200，吧生成的状态码返回
            if (statusCode == 200) {

                return ResultEntity.successWithData(verifyCode);

            }
            // 否则返回错误信息
            return ResultEntity.failed(reasonPhrase);

        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());

        }

    }


    /**
     * 此方法是对明文字符串进行MD5加密
     *
     * @param source 明文字符串
     * @return 加密的结果
     */
    public static String md5(String source) {

        // 判断传过来的参数是否为有效字符串
        if (source == null || source.length() == 0) {
            // 如果不是则直接抛出异常
            throw new RuntimeException(CrowdConstant.MESSAGE_STRING_INVALIDATE);
        }

        try {
            String algorithm = "md5";
            //获取MessageDigest对象
            MessageDigest instance = MessageDigest.getInstance(algorithm);
            //将明文字符串转换为对应的字节数组
            byte[] bytes = source.getBytes();
            // 执行加密
            byte[] digest = instance.digest(bytes);
            //创建BigInteger
            int signum = 1;
            BigInteger bigInteger = new BigInteger(signum, digest);
            //按照十六进制将BigInteger转换为字符串
            int radix = 16;
            String encoded = bigInteger.toString(radix).toUpperCase();
            return encoded;

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 判断当前请求是否为ajax请求
     *
     * @param request
     * @return true：表示为ajax请求
     * false：表示为普通请求
     */
    public static boolean judgeRequestType(HttpServletRequest request) {
        //获取请求头信息
        String accept = request.getHeader("Accept");
        String header = request.getHeader("X-Requested-With");

        return (accept != null && accept.contains("application/json"))
                ||
                (header != null && header.equals("XMLHttpRequest"));

    }

}
